/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package trocabi.service;

import trocabi.service.PrinterParameters;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.print.PrintService;
import javax.print.attribute.Attribute;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.Fidelity;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.DialogTypeSelection;
import javax.print.attribute.standard.JobName;
import javax.print.attribute.ResolutionSyntax;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.OrientationRequested;
import trocabi.Socle.TechnicalException;
import trocabi.model.Article;
import trocabi.printer.Barcode;

/**
 *
 * @author philippe
 */
public class PrinterService implements Printable {
    public  static final double JAVA_DPI = 72.0;  // Résolution d'un contexte graphique Java
    // Police d'affichage du texte
    private Font font = new Font(Font.MONOSPACED, Font.BOLD, 16);
    public PrinterService(String jobName) {
         aset = new HashPrintRequestAttributeSet();
         aset.add(new JobName(jobName, null));
         printerJob = PrinterJob.getPrinterJob();
         parameters=new PrinterParameters();
    }
      
    public void setProperty(Attribute a) { 
        aset.add(a);
    }
   
    public void print() throws PrinterException {
       printerJob.setPrintable(this);
       printerJob.print(aset);
    }
    
    public void printImage(BufferedImage _image) throws PrinterException {
       image=_image;
       printerJob.setPrintable(this);
       printerJob.print(aset);
    }
    
    /**
    * Méthode qui restaure le contexte graphique dans sa résolution réelle.
    *
    * @param graphics le contexte graphique
    * @param pageFormat information sur le format de la page
    * @return le rectangle de la zone imprimable dans la résolution réelle
    */
   protected Rectangle restoreRealDpi(Graphics2D graphics, PageFormat pageFormat){
      Rectangle retValue = new Rectangle();
      
      // Détermine la résolution réelle
      Rectangle deviceBounds = graphics.getDeviceConfiguration().getBounds();
      double pageWidth72Dpi  = pageFormat.getWidth();
      double pageHeight72Dpi = pageFormat.getHeight();
      
      double widthResolution  = (JAVA_DPI * deviceBounds.getWidth())/pageWidth72Dpi;
      double heightResolution = (JAVA_DPI * deviceBounds.getHeight())/pageHeight72Dpi;
      
      // Détermine les dimensions réelles de la zone imprimable (en points)
      double realImageableX      = (pageFormat.getImageableX()*widthResolution)/ JAVA_DPI;
      double realImageableWidth  = (pageFormat.getImageableWidth()*widthResolution)/ JAVA_DPI;
      double realImageableY      = (pageFormat.getImageableY()*heightResolution)/ JAVA_DPI;
      double realImageableHeight = (pageFormat.getImageableHeight()*heightResolution)/ JAVA_DPI;
      
      System.out.println(String.format("x=%f y=%f w=%f h=%f",
              realImageableX,realImageableY,realImageableWidth,realImageableHeight));
      
      
      float[] size=margin.getPrintableArea(MediaPrintableArea.INCH);
      realImageableX      = (size[0]*widthResolution);
      realImageableY      = (size[1]*heightResolution);
      realImageableWidth  = (size[2]*widthResolution);
      realImageableHeight = (size[3]*heightResolution);
      
        System.out.println(String.format("x=%f y=%f w=%f h=%f",
              realImageableX,realImageableY,realImageableWidth,realImageableHeight));
      // Modifie la transformation du contexte graphique
      graphics.setTransform(new AffineTransform()); // Passe en résolution réelle
      
      switch (pageFormat.getOrientation()){
         case PageFormat.LANDSCAPE : {
            // Les marges retournées par pageFormat prennent en compte la rotation
            // Il faut les inverser
            double temp = realImageableX;
            realImageableX = realImageableY;
            realImageableY = temp;
            temp = realImageableWidth;
            realImageableWidth = realImageableHeight;
            realImageableHeight = temp;
            
            // Effectue la rotation
            graphics.rotate(-Math.PI / 2.0);
            
            // Translation pour s'aligner sur les marges
            graphics.translate(-realImageableWidth + realImageableX, realImageableY);
            break;
         }
         case PageFormat.REVERSE_LANDSCAPE : {
            // Les marges retournées par pageFormat prennent en compte la rotation
            // Il faut les inverser
            double temp = realImageableX;
            realImageableX = realImageableY;
            realImageableY = temp;
            temp = realImageableWidth;
            realImageableWidth = realImageableHeight;
            realImageableHeight = temp;
            
            // Effectue la rotation
            graphics.rotate(Math.PI / 2.0);
            // Translation pour s'aligner sur les marges
            graphics.translate(realImageableX, realImageableY - realImageableHeight);
            break;
         }
         default : {
            // Mode portrait
            // Translation pour s'aligner sur les marges
            graphics.translate(realImageableX, realImageableY);
         }
      }
      retValue.x      = (int)Math.ceil(realImageableX);
      retValue.y      = (int)Math.ceil(realImageableY);
      retValue.width  = (int)Math.floor(realImageableWidth);
      retValue.height = (int)Math.floor(realImageableHeight);

      return retValue;
    }
   
   
    @Override
    public int print(Graphics grphcs, PageFormat pf, int pageIndex) throws PrinterException {
        if (pageIndex == 0) {
            Graphics2D g2d = (Graphics2D) grphcs;
            g2d.translate(0, 0);
            Rectangle margin = restoreRealDpi((Graphics2D)g2d, pf);
            
            // Dessine le rectangle
            
            g2d.drawRect(0,
                              0,
                              margin.width,
                              margin.height);
            // Affiche les marges
            g2d.setFont(font);
            // g2d.drawString(margin.toString(), 0, margin.height/2);
            g2d.translate(pf.getImageableX(), pf.getImageableY());
            g2d.drawRenderedImage(image, null);
            return Printable.PAGE_EXISTS;
        } else {
            return Printable.NO_SUCH_PAGE;
        }
    }
    
    public void selectPrinter(String printerName) throws TechnicalException, PrinterException {
        javax.print.PrintService []printers = PrinterJob.lookupPrintServices();
        for (int i=0; i<printers.length;i++) {
            System.out.println("selected printer: " + printers[i]);
            if (printers[i].getName().compareTo(printerName)==0) {
                printer=printers[i];
                printerJob.setPrintService(printer); 
                parameters=new PrinterParameters(aset,printer);
                margin=getPhysicalMargin();
                return;
            }
        }
        throw new TechnicalException(String.format("Imprimante '%s' non trouvée",printerName));
    }
    
    public MediaPrintableArea getPhysicalMargin() { // Récupère les marges physiques de l'imprimante
         MediaPrintableArea printableZone = (MediaPrintableArea)aset.get(MediaPrintableArea.class);
         if (printableZone == null){
            printableZone = (MediaPrintableArea) printer.getDefaultAttributeValue(MediaPrintableArea.class);  
         }
         return printableZone;
    }
    
    public MediaPrintableArea getPaperSize() {
         PageFormat pageFormat = printerJob.getPageFormat(aset); 
         double paperWidth_inch = pageFormat.getWidth() / JAVA_DPI;    // inch
         double paperHeight_inch = pageFormat.getHeight() / JAVA_DPI;
         
         return new MediaPrintableArea((float) 0.,(float)0.,
                                       (float) paperWidth_inch,
                                       (float) paperHeight_inch,MediaPrintableArea.INCH);
    }
    
    public void setMargin(MediaPrintableArea _margin) {
        float[] physicalMargin=getPhysicalMargin().getPrintableArea(MediaPrintableArea.MM);
        float[] requiredMargin=_margin.getPrintableArea(MediaPrintableArea.MM);
        
        if (requiredMargin[0]<physicalMargin[0]) requiredMargin[0]=physicalMargin[0];
        if (requiredMargin[1]<physicalMargin[1]) requiredMargin[1]=physicalMargin[1];
        if (requiredMargin[2]>physicalMargin[2]) requiredMargin[2]=physicalMargin[2];
        if (requiredMargin[3]>physicalMargin[3]) requiredMargin[3]=physicalMargin[3];
        margin=new MediaPrintableArea(requiredMargin[0],requiredMargin[1],
                                      requiredMargin[2],requiredMargin[3],MediaPrintableArea.MM);
        
    }
    
    public MediaPrintableArea getMargin() {
        return margin;
    }
    public void showPageDialog() {
        printerJob.pageDialog(aset);
    }
    
    public boolean showPrintDialog() {
        return printerJob.printDialog(aset);
    }
    
    public PrinterParameters getParameters() { return parameters; }
    
    public static void main(String arg[]) {
        Article article=new Article(74840,74840,"Vetement Neuf", "N","H","V","Noir",Article.Etat.DEPOT, "blabla", null, 10.0, 0.15, new Date(), null,null,null);
        Barcode barcode=new Barcode(article);
        
        PrinterService printerService = new PrinterService("testImpression");
        try {
            printerService.selectPrinter("Brother QL-700"); // "PDFCreator
            // printerService.selectPrinter("Samsung SCX-4623 Series"); // "PDFCreator
            // printerService.selectPrinter("PDFCreator"); // "PDFCreator
            PrinterParameters param=printerService.getParameters();            
            // printerService.setMargin(new MediaPrintableArea((float) 1.52,(float)2.96,(float)25.908,(float) 88.90,MediaPrintableArea.MM));
            printerService.setProperty(new Copies(1));
            printerService.setProperty(DialogTypeSelection.NATIVE);
            printerService.setProperty(new Copies(1));
            // printerService.showPageDialog();
            printerService.setProperty(printerService.getMargin());
            
            
            if (printerService.showPrintDialog())  printerService.printImage(barcode.toBufferedImg());
            //barcode.toBmpFile("c:/temp/img.bmp");
        } catch (TechnicalException ex) {
            Logger.getLogger(PrinterService.class.getName()).log(Level.SEVERE, null, ex);
        } catch (PrinterException ex) {
            Logger.getLogger(PrinterService.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    protected PrinterJob         printerJob;
    protected PrintService       printer;
    protected PrinterParameters  parameters;
    protected MediaPrintableArea margin;
    PrintRequestAttributeSet     aset;
    BufferedImage                image;
}
